#include <iostream>                // std::cout
#include <thread>                // std::thread
#include <mutex>                // std::mutex, std::unique_lock
#include <condition_variable>    // std::condition_variable

std::mutex mtx; // 全局互斥锁.
std::condition_variable cv; // 全局条件变量.
bool ready = false; // 全局标志位.

/*
    std::condition_variable(条件变量)，它必须与std::mutex(互斥锁)连在一起使用，
    std::condition_variable 的拷贝构造函数被禁用，只提供了默认构造函数，也就是说它只能被默认构造。
    它有wait*()系列方法和notify*()系列方法，并且同一个std::condition_variable对象的wait*()方法和notigy*()方法要配合使用：

    最简单的是： void wait (unique_lock<mutex>& lck); 假设有两个线程：A和B，和一个std::condition_variable对象cv,
    当线程A以lck这个锁为参数调用cv的wait方法时，线程A需要先获得了lck锁，调用了wait方法后，wait方法会先执行lck.unlock()释放锁，
    使得另一个需要lck锁的线程B执行下去，并且wait方法会又立即需要获得lck锁（这样线程A就被阻塞了），然后在线程B的执行过程中
    需要调用cv的notigy_one()，使得被阻塞在wait方法的线程A继续执行下去。
    
    
    
*/

void do_print_id(int id)
{
    std::unique_lock <std::mutex> lck(mtx);
    while (!ready) // 如果标志位不为 true, 则等待...
        cv.wait(lck); // 当前线程被阻塞, 当全局标志位变为 true 之后,
    // 线程被唤醒, 继续往下执行打印线程编号id.
    std::cout << "thread " << id << '\n';
}

void go()
{
    std::unique_lock <std::mutex> lck(mtx);
    ready = true; // 设置全局标志位为 true.
    cv.notify_all(); // 唤醒所有线程.
}

int main()
{
    std::thread threads[10];
    // spawn 10 threads:
    for (int i = 0; i < 10; ++i)
        threads[i] = std::thread(do_print_id, i);

    std::cout << "10 threads ready to race...\n";
    go(); // go!

  for (auto & th:threads)
        th.join();

    return 0;
}